package com.lleice.common.utils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.alibaba.fastjson.JSONObject;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;

/**
 * 树结构工具类
 * @author lizihao
 *
 */
public class TreeListUtil<T> {
	
	
	/**
	 * 获取树结构 泛型
	 * @param <T>
	 * @param list
	 * @return
	 * @throws IllegalAccessException 
	 * @throws NoSuchFieldException 
	 */
	public static <T> List<T> getTreeList(List<?> list,Map<Object,Object> configMap,List<String> extraKey,Class<T> beanClass) throws Exception{
		List<T> result = new ArrayList<>();
		if(!CollUtil.isEmpty(list)) {
			TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
			// 自定义属性名 都要默认值的
			treeNodeConfig.setNameKey((String)configMap.get("nameKey"));
			//排序得key,根据表决定
			treeNodeConfig.setWeightKey((String)configMap.get("weightKey"));
			//相当于子id
			treeNodeConfig.setIdKey((String)configMap.get("idKey"));
			//相当于父id
			treeNodeConfig.setParentIdKey((String)configMap.get("parentIdKey"));

			List<TreeNode<String>> nodeList = CollUtil.newArrayList();
			for(Object o : list) {
				Class<? extends Object> clazz = o.getClass();
				//排序乘以-1是因为 默认是数值最小排最上
				Map<String,Object> extra = new HashMap<String,Object>(16);
				extraKey.forEach(a ->{
					Field field = null;
					try {
						field = clazz.getDeclaredField(a);
					} catch (NoSuchFieldException e) {
						throw new RuntimeException(e.getMessage());
					} catch (SecurityException e) {
						throw new RuntimeException(e.getMessage());
					}
					field.setAccessible(true);
					try {
						extra.put(a, field.get(o));
					} catch (IllegalArgumentException e) {
						throw new RuntimeException(e.getMessage());
					} catch (IllegalAccessException e) {
						throw new RuntimeException(e.getMessage());
					}
				});
				setNode(configMap, nodeList, o, clazz, extra);
			}
			//0 表示从最顶级开始拿 也表示父id等于0的开始拿
			List<Tree<String>> treeNodes = TreeUtil.build(nodeList, "0", treeNodeConfig,
			        (treeNode, tree) -> {
			        	tree.setName(treeNode.getName());
			        	tree.setWeight(treeNode.getWeight());
			            tree.setId(treeNode.getId());
			            tree.setParentId(treeNode.getParentId());
			            // 扩展属性 ...
			            extraKey.forEach(a ->{
			            	tree.putExtra(a, treeNode.getExtra().get(a));
			            });
			        });
			for(Tree<String> t : treeNodes) {
				result.add(JSONObject.parseObject(JSONObject.toJSONString(t), beanClass));
			}
		}
		return result;
	}


	private static <T> void setNode(Map<Object, Object> configMap, List<TreeNode<String>> nodeList, T o,
			Class<? extends Object> clazz, Map<String, Object> extra)
			throws Exception {
		Field idField = clazz.getDeclaredField((String) configMap.get("idKey"));
		idField.setAccessible(true);
		Field parentIdField = clazz.getDeclaredField((String)configMap.get("parentIdKey"));
		parentIdField.setAccessible(true);
		Field nameKeyField = clazz.getDeclaredField((String)configMap.get("nameKey"));
		nameKeyField.setAccessible(true);
		Field weightKeyField = clazz.getDeclaredField((String)configMap.get("weightKey"));
		weightKeyField.setAccessible(true);
		nodeList.add(new TreeNode<>(idField.get(o).toString(),parentIdField.get(o).toString(), nameKeyField.get(o).toString(),
				weightKeyField.get(o) == null? null : weightKeyField.get(o).toString()).
				setExtra(extra));
	}
}
